package com.example.taxfloatproject20240926.ui.socket;

import android.util.Log;

import java.nio.charset.Charset;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;

//@Component
public class NettyTCPClient {
    private final EventLoopGroup group = new NioEventLoopGroup();
    private ChannelFuture mChannelFuture = null;
    private final ThreadLocal<Channel> mChannel = new ThreadLocal<>();


    /**
     * 客户端通过 Channel 对象向服务器端发送数据
     *
     * @param data 文本数据
     */
    public void send(String data) {
        try {
            if (mChannel.get() == null) {
                mChannel.set(mChannelFuture.channel());
            }
            mChannel.get().writeAndFlush(data);
        } catch (Exception e) {
            Log.e(CmdUtils.TAG, this.getClass().getName().concat(".send has error"), e);
        }
    }
    // 客户端启动，并连上服务器端
    public void init(String host,int port) {
        ForkJoinPool.commonPool().submit(() -> startClient(host,
                port));
    }

    /**
     * NettyClient 封装
     */
    private void startClient(String host, int port) {
// Configure the client.
        try {
            if (CmdUtils.isConnect) return;
            RetryStrategy retryStrategy = new RetryStrategy();
            retryStrategy.setRetryAddTime(1);
            retryStrategy.setRetryMaxCount(Integer.MAX_VALUE);
            Bootstrap b = retryStrategy.buildBootstrapAndReturnBootstrap(new Bootstrap());
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast("decoder", new StringDecoder(Charset.forName("gbk")));
                            p.addLast("encoder", new StringEncoder());
                            //读超时时间60秒，会触发IdleStateEvent事件并且交给下一个handler处理
                            //下一个handler必须实现userEventTriggered方法处理对应事件
                            p.addLast(new IdleStateHandler(0, 60, 0, TimeUnit.SECONDS));
                            // 添加自定义重试连接处理器
                            p.addLast(new HeartNettyClientHandler(retryStrategy));
                        }
                    });

            b.remoteAddress(host,port);//存储目标连接信息，以便下次调用connect。
            mChannelFuture = b.connect();
            mChannelFuture.addListener(listener -> {
                if (!listener.isSuccess()) {
                    CmdUtils.isConnect = false;
                    ChannelHandlerContext context = mChannelFuture.channel().pipeline().context(HeartNettyClientHandler.class);
                    retryStrategy.processRetryConnect(context);
                } else {
                    Log.i(CmdUtils.TAG, String.format("客户端启动成功，并监听端口：%s ", port));
                    CmdUtils.isConnect = true;
                }
            });
            // channelFuture.sync();//使用ChannelFuture.sync()方法可以确保主线程等待连接建立完成后再继续执行后续的代码。

        } catch (Exception e) {
            Log.e(CmdUtils.TAG,"启动 netty 客户端出现异常", e);
        }
    }

    public void destroy() {
        if (group == null) return;
        group.shutdownGracefully();
    }


}

